package core.proto;


import static app.constants.CollabVizConstants.*;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.tree.DefaultMutableTreeNode;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.jdesktop.swingx.*;
import org.jdesktop.swingx.mapviewer.DefaultWaypointRenderer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.mapviewer.Waypoint;
import org.jdesktop.swingx.mapviewer.WaypointPainter;
import org.jdesktop.swingx.mapviewer.WaypointRenderer;

import prefuse.util.ui.UILib;
import app.constants.CollabVizConstants;
import app.exceptions.CollabVizException;
import app.util.PropertyLoaderUtil;
import core.proto.search.DocumentSearchDocumentListener;
import core.proto.search.QueryLoggerDocumentListener;
import core.proto.search.SearchBar;
import core.proto.vis.VizDemoRadial;
import core.util.logging.UserLogWriter;
import core.util.logging.constants.Action;
import core.util.logging.constants.Location;

public class AllComponents extends JPanel implements MouseListener {


	//static final String HILITE_ICON = "/img/highlighter.png";
	public static Color color_text_highlight = new Color(195,217,255);

	private static PaintDoc updatedDocument = new PaintDoc(DUMMY_FILE_NAME);

	private static final long serialVersionUID = 1L;

	private static PaintDoc document;

	private static ClosableTabbedPane multipleDocs = new ClosableTabbedPane();

	public static ArrayList<String> openTabs = new ArrayList<String>();

	static String imagePath;

	public static String getHtmlRootFolderPath() {
		return 	HTML_FILES_FOLDER;
	}

	static JPanel directory;


	// private static JEditorPane document = new JEditorPane();

	private static JPanel viz = VizDemoRadial.demo(VizDemoRadial.DATA_FILE,
			"name", Util.getVizWidth(), Util.getVizHeight());

	// Note: it appears that static JTabbedPanes are rendered differently 
	// on my windows machine than non-static JTabbedPanes. I like the 
	// static JTabbedPane appearance so let's keep that. 

	//	private static JTabbedPane notes = new JTabbedPane();

	static JXMapKit jxMap;

	static JTabbedPane vizTabbedPane = new JTabbedPane();
	static JTabbedPane fileTreeTabbedPane = new JTabbedPane();
	//	static JTabbedPane favoritesTabbedPane = new JTabbedPane();

	// TODO change to timeline later. 
	static JComponent timeline;

	// Newer TODO
	private static JSplitPane dirDocSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
	private static JSplitPane timeLineSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
	private static JSplitPane vizNoteSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
	private static JSplitPane leftRightSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

	public static JSplitPane docVizSplitPane = new JSplitPane();

	private static String htmlFilePath;

	private static JEditorPane historyText;

	private static JScrollPane historyScroll;

	private static VizDemoRadial visual; 

	private static NotesArea notesArea;

	static MotionCanvas canvas;
	//	static NotePad notePad; // todo old 

	public static final int ALL_VIEW = 0;
	public static final int NO_VIZ_VIEW = 1;
	public static final int NO_NOTES_VIEW = 2;
	public static final int NO_VIZNOTES_VIEW = 3;

	private Set<WaypointWithAnno> waypoints; 

	private JLayeredPane layered; 

	public AllComponents( int selectedView, boolean screenCap) throws IOException, CollabVizException {
		super();

		timeline = new TimeLine(2008,3);
		waypoints = new HashSet<WaypointWithAnno>();


		UILib.setPlatformLookAndFeel();

		UserLogWriter.setScreenCap(screenCap);

		directory = new FileTree(new File(getHtmlRootFolderPath()), 1);

		imagePath = Util.getResourceUrl(CollabVizConstants.COMMENTS_IMG).getPath();

		document = new PaintDoc(DUMMY_FILE_NAME);
		document.addMouseListener(this);


		for (int i = 0; i < viz.getComponentCount(); i++) {
			if (viz.getComponent(i) instanceof VizDemoRadial) {
				visual = (VizDemoRadial) viz.getComponent(i);
			}
		}

		viz.addComponentListener(new ComponentListener() {
			@Override
			public void componentShown(ComponentEvent e_) {
			}

			@Override
			public void componentResized(ComponentEvent e) {
				visual.resizeAndRun(viz.getWidth(), viz.getHeight());
				docVizSplitPane.updateUI();
			}

			@Override
			public void componentMoved(ComponentEvent e_) {
			}

			@Override
			public void componentHidden(ComponentEvent e_) {
			}
		});

		setSize(WINDOW_WIDTH, WINDOW_HEIGHT);

		setProperties(vizTabbedPane, Util.getVizWidth(), Util.getVizHeight());
		vizTabbedPane.addTab("Visualization", viz);

		setProperties(fileTreeTabbedPane, Util.getFileTreeWidth(), Util.getFileTreeHeight());
		fileTreeTabbedPane.addTab("Directory", directory);

		setProperties(timeline, Util.getFavoritesWidth(), Util.getFavoritesHeight());
		timeline.setBackground(Color.white);
		//		setProperties(favoritesTabbedPane, Util.getFavoritesWidth(), Util.getFavoritesHeight());
		//		favoritesTabbedPane.addTab("Favorites", favorites);

		// TODO old stuff for notepad 
		//		setProperties(notes, Util.getNoteAreaWidth(), Util.getNoteAreaHeight());
		//		notes = addNotesComponent(notes);


		jxMap = makeMapComponent();
		setProperties(jxMap, Util.getNoteAreaWidth(), Util.getNoteAreaHeight());
		setUpWayPointRenderer();
		layered = new JLayeredPane();
		layered.add(jxMap, JLayeredPane.PALETTE_LAYER);

		//		setProperties(jxMap, Util.getNoteAreaWidth(), Util.getNoteAreaHeight());
		setProperties(layered, Util.getNoteAreaWidth(), Util.getNoteAreaHeight());

		setProperties(multipleDocs, Util.getDocWidth(), Util.getDocHeight());

		document.setDragEnabled(true);
		document.setEditable(true);

		// create Panel for drop targets to save
		createFavoritesPanel();

		favorites.add(favoritesPanel);

		multipleDocs.setBackground(Color.GRAY);
		ChangeListener changeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent changeEvent) {
				ClosableTabbedPane tabbedPane = (ClosableTabbedPane) changeEvent.getSource();
				int index = tabbedPane.getSelectedIndex();
				if (index == -1){
					saveCurrentPath(DUMMY_FILE_NAME);
					vizSetNoTabOpen(true);
					vizUnhide();
				}else{
					String absPath = openTabs.get(index);
					saveCurrentPath(absPath);
					getFileTree().expandTreeByPath(absPath, true);

				}
			}
		};
		multipleDocs.addChangeListener(changeListener);

		if (selectedView == ALL_VIEW) {						
			// top: viz; bottom: notes
			//			splitScreen(vizNoteSplitPane, vizTabbedPane, notes, false, Util.getVizHeight()); 
			//			splitScreen(vizNoteSplitPane, vizTabbedPane, jxMap, false, Util.getVizHeight());
			splitScreen(vizNoteSplitPane, vizTabbedPane, layered, false, Util.getVizHeight());
		} else if (selectedView == NO_VIZ_VIEW) {
			JPanel gray = new JPanel();
			setProperties(gray, Util.getVizWidth(), Util.getVizHeight());
			//			splitScreen(vizNoteSplitPane, gray, notes, false, Util.getVizHeight());
			//			splitScreen(vizNoteSplitPane, gray, jxMap, false, Util.getVizHeight());
			splitScreen(vizNoteSplitPane, gray, layered, false, Util.getVizHeight());
		} else if (selectedView == NO_NOTES_VIEW) {
			JPanel gray = new JPanel();
			setProperties(gray, Util.getNoteAreaWidth(), Util.getNoteAreaHeight());
			splitScreen(vizNoteSplitPane, vizTabbedPane, gray, false, Util.getVizHeight());
		} else if (selectedView == NO_VIZNOTES_VIEW) {
			JPanel gray = new JPanel();
			setProperties(gray, Util.getVizWidth(), Util.getVizHeight() + Util.getNoteAreaHeight());
		}
		// left: file tree; right: doc pane
		splitScreen(dirDocSplitPane, fileTreeTabbedPane, multipleDocs, true, Util.getFileTreeWidth());			
		//		splitScreen(timeLineSplitPane, dirDocSplitPane, favoritesTabbedPane, false, Util.getFileTreeHeight());
		splitScreen(timeLineSplitPane, dirDocSplitPane, timeline, false, Util.getFileTreeHeight());
		splitScreen(leftRightSplitPane, timeLineSplitPane, vizNoteSplitPane, true, Util.getFileTreeWidth() + Util.getDocWidth());
		add(leftRightSplitPane);


		setUpUserLogMouseEnterListener();
		setVisible(true);

		// Debug. 
		Util.p(Util.getFileTreeWidth() + " " + Util.getFileTreeHeight());
	}

	private void setUpUserLogMouseEnterListener(){
		long mouseMask = AWTEvent.MOUSE_EVENT_MASK;

		final Hashtable<JComponent,Location> locs = new Hashtable<JComponent,Location>();
		locs.put(vizTabbedPane, Location.Viz);
		locs.put(fileTreeTabbedPane, Location.Directory);
		//		locs.put(notePad, Location.Notes);
		locs.put(jxMap, Location.Notes);
		locs.put(favorites, Location.Favorites);
		locs.put(multipleDocs, Location.Documents);

		Toolkit.getDefaultToolkit().addAWTEventListener( 

				new AWTEventListener()
				{
					Location currentLoc = null;

					public void eventDispatched(AWTEvent e)
					{
						if (e.getSource() instanceof JComponent){
							// Safe cast because we set the mask to only handle mouse events for this handler. 
							MouseEvent m = (MouseEvent) e;


							switch(m.getID()){
							// Track the mouse enter/exit from various areas. 
							case MouseEvent.MOUSE_ENTERED:
								for (Entry<JComponent, Location> ent : locs.entrySet()){
									// check if we entered one of the areas we want. 
									if (SwingUtilities.isDescendingFrom((JComponent) e.getSource(), ent.getKey())){
										// check if we are already inside this general area. 
										if (ent.getValue() != currentLoc){
											if (currentLoc != null){
												// This happens when we drag item across 
												// UI areas, and for some reason the mouse enter/exit
												// events don't get raised in this case. 
												// So we explicitly check for this and 
												// just put an entry for when we left the last UI area
												// (so we count the dragging time as time spent in 
												// the UI area where the drag started). 
												UserLogWriter.log2("",	currentLoc, Action.MOUSEEXIT);
											}

											currentLoc = ent.getValue();
											UserLogWriter.log2("", currentLoc, Action.MOUSEENTER);
										}
										break;
									}
								}
								break;
							case MouseEvent.MOUSE_EXITED:
								for (Entry<JComponent, Location> ent : locs.entrySet()){
									// check if we left the general area. 
									if (SwingUtilities.isDescendingFrom((JComponent) e.getSource(), ent.getKey())){
										// Get point in the coordinate system of the enclosing component we wanna check. 
										Point p = SwingUtilities.convertPoint((Component) e.getSource(), m.getPoint(), ent.getKey());

										if (! ent.getKey().getBounds().contains(p)){
											UserLogWriter.log2("", currentLoc, Action.MOUSEEXIT);
											currentLoc = null;	
										}
										break;
									}
								}
								break;
							default:
								break;
							}
						}
					}
				}, 
				mouseMask);
	}



	public static String getHtmlFilePath () {
		return htmlFilePath;
	}

	/**
	 * Method to set the dimensions for the 5 areas. 
	 * @param p
	 * @param w
	 * @param h
	 */
	private void setProperties(JComponent p, int w, int h) {
		Dimension d = new Dimension(w, h);
		p.setPreferredSize(d);
		p.setSize(d);
		p.setMinimumSize(d);
	}

	public void splitScreen(JSplitPane sp, Component a, Component b, boolean leftRight,
			int dividerPos) {
		if (! leftRight) {
			sp.setTopComponent(a);
			sp.setBottomComponent(b);
			sp.setSize(a.getWidth(), a.getHeight() + b.getHeight());
			sp.setPreferredSize(getSize());
		} else {
			sp.setLeftComponent(a);
			sp.setRightComponent(b);
			sp.setSize(a.getWidth() + b.getWidth(), a.getHeight());
			sp.setPreferredSize(getSize());
		}
		sp.setDividerLocation(dividerPos);
	}

	String getCopyTxt2NotepadToggleTxt () {
		if (PaintDoc.copyHighlightTextToNotepad){
			return "Copy hilite text";
		}else {
			return "No copy hilite text";
		}
	}

	private JXMapKit makeMapComponent() {
		final JXMapKit mapKit = new JXMapKit();
		final double MINDIST = 8; 
		
		final JXMapViewer map = mapKit.getMainMap();
		
		mapKit.getMainMap().addMouseMotionListener(new MouseAdapter(){
			WaypointWithAnno waypointInFocus; 

			/**
			 * This method handles the logic for hiding annotations when we drag the map and 
			 * the waypoint moves beyond the visible area. 
			 */
			public void mouseDragged(MouseEvent me){
				for(WaypointWithAnno wp : waypoints){
					GeoPosition upperLeft = map.convertPointToGeoPosition(new Point(0, 0));
					GeoPosition lowerRight = map.convertPointToGeoPosition(new Point(map.getWidth(), map.getHeight()));

					boolean canShow = lte(wp.getPosition().getLatitude(), Math.max(upperLeft.getLatitude(), lowerRight.getLatitude())) &&
							 lte(Math.min(upperLeft.getLatitude(), lowerRight.getLatitude()), wp.getPosition().getLatitude()) &&
							 lte(wp.getPosition().getLongitude(), Math.max(upperLeft.getLongitude(), lowerRight.getLongitude())) &&
							 lte(Math.min(upperLeft.getLongitude(), lowerRight.getLongitude()), wp.getPosition().getLongitude());
					
					if (! wp.getPanel().isVisible() && canShow){
						wp.getPanel().setVisible(true);
					} else if (wp.getPanel().isVisible() && ! canShow){
						wp.getPanel().setVisible(false);
					}
				}
			}
			
			public void mouseMoved(MouseEvent me) {
				WaypointWithAnno closest = null;
				Point p = me.getPoint();

				if (waypointInFocus != null){
					waypointInFocus.hideTextArea();
					waypointInFocus = null;
				} 

				for(WaypointWithAnno wp : waypoints){
					if (mapKit.getMainMap().convertGeoPositionToPoint(wp.getPosition()).distance(p) < MINDIST){
						closest = wp;
						break;
					}
				}
				if (closest != null){
					Point2D loc = mapKit.getMainMap().convertGeoPositionToPoint(closest.getPosition());
					closest.showTextArea((int) loc.getX(), (int) loc.getY());
					waypointInFocus = closest;
				}
			}
		});

		mapKit.getMainMap().addMouseListener(new MouseAdapter(){

			public void mouseClicked(MouseEvent me){

				// two cases. 
				// case 1: click close enough to the tip of a way point, so open the annotation. 
				// case 2: not close enough to other waypoints, make a new one.
				WaypointWithAnno closest = null;
				Point p = me.getPoint();

				for(WaypointWithAnno wp : waypoints){
					if (mapKit.getMainMap().convertGeoPositionToPoint(wp.getPosition()).distance(p) < MINDIST){
						closest = wp;
						break;
					}
				}

				if (closest == null && me.getButton() == MouseEvent.BUTTON1){
					// Add new things on left click. 
					GeoPosition pos = mapKit.getMainMap().convertPointToGeoPosition(me.getPoint());
					WaypointWithAnno wp = new WaypointWithAnno(pos);
					waypoints.add(wp);				
					layered.add(wp.getPanel(), JLayeredPane.MODAL_LAYER);
					wp.showTextArea(me.getX(), me.getY());
				}
				mapKit.getMainMap().repaint();
			}
		});

		// Taken and modified from: 
		// http://swingdepot.blogspot.com/2009/08/openstreet-maps-example-java-swings.html
		mapKit.setDefaultProvider(org.jdesktop.swingx.JXMapKit.DefaultProviders.OpenStreetMaps);
		mapKit.setAddressLocationShown(false);
		mapKit.setDataProviderCreditShown(false);
		mapKit.setCenterPosition(new GeoPosition(0,0));
		mapKit.setMiniMapVisible(false);
		mapKit.setZoomSliderVisible(true);
		mapKit.setZoomButtonsVisible(true);
		mapKit.setZoom(2);

		// google map tells 739 Ellsworth Avenue, Pittsburgh, PA has 
		// lattiude: 40.33430	longitude: -79.60484
		mapKit.setAddressLocation(new GeoPosition(40.33430, -79.60484));
		return mapKit;
	}

	private void setUpWayPointRenderer(){
		WaypointPainter painter = new WaypointPainter();
		painter.setWaypoints(waypoints);

		painter.setRenderer(new WaypointRenderer() {
			DefaultWaypointRenderer renderer; 
			{
				renderer = new DefaultWaypointRenderer();
			}
			public boolean paintWaypoint(Graphics2D g, JXMapViewer map, Waypoint wp) {
				renderer.paintWaypoint(g, map, wp);
				Point2D pt = map.convertGeoPositionToPoint(wp.getPosition());

				GeoPosition upperLeft = map.convertPointToGeoPosition(new Point(0, 0));
				GeoPosition lowerRight = map.convertPointToGeoPosition(new Point(map.getWidth(), map.getHeight()));
				
				JPanel panel = ((WaypointWithAnno) wp).getPanel();
				if (panel.isVisible()){
					((WaypointWithAnno) wp).getPanel().setLocation((int) pt.getX(), (int) pt.getY());
				}
				return true;
			}
		});

		jxMap.getMainMap().setOverlayPainter(painter);
	}

	private boolean lte(double left, double right){
		return Double.compare(left, right) <= 0;
	}

	//	private JTabbedPane addNotesComponent (final JTabbedPane notesPanel) {
	//		historyText = new JEditorPane();
	//		historyText.setDragEnabled(true);
	//		historyText.setEditable(false);
	//
	//		notePad = new NotePad();
	//
	//		historyScroll = new JScrollPane();
	//		historyScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
	//		historyScroll.setViewportView(notePad);
	//		historyScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
	//		notesPanel.addTab("Notepad", historyScroll);
	//
	//		historyScroll.addComponentListener(new ComponentAdapter(){
	//			public void componentResized (ComponentEvent ce){
	//				notePad.setSize(historyScroll.getViewport().getSize());
	//				notePad.invalidate();
	//				notePad.repaint();
	//			}
	//		});
	//
	//		// Temporary for holding the toggle for whether to copy text to notepad when highlighting doc. 
	//		notesPanel.addTab("", null);
	//		final JButton toggle = new JButton(getCopyTxt2NotepadToggleTxt());
	//		toggle.addMouseListener(new MouseAdapter(){
	//			public void mouseClicked (MouseEvent me) {
	//				PaintDoc.setCopyHighlightTextToNotepad();
	//				toggle.setText(getCopyTxt2NotepadToggleTxt());
	//			}
	//		});
	//		notesPanel.setTabComponentAt(1, toggle);
	//		notesPanel.setEnabledAt(1, false);
	//
	//		return notesPanel;
	//	}


	public static void addTextToNotepad (final String caseAbsPath, final String text) {
		//		SwingUtilities.invokeLater(new Runnable(){
		//			public void run() {
		//				notePad.insertText(caseAbsPath, text);
		//			}
		//		});
	}

	private static JPanel favoritesPanel = null;

	private void createFavoritesPanel() {
		// create drop panel - the save panel
		favoritesPanel = new JPanel();
		setProperties(favoritesPanel, Util.getFavoritesWidth(), Util.getFavoritesHeight());

		canvas = new MotionCanvas(Color.white);
		canvas.setPreferredSize(new Dimension(Util.getFavoritesWidth(), Util.getFavoritesHeight()));
		canvas.setBorder(LineBorder.createGrayLineBorder());
		canvas.setTransferHandler(new FileTransferHandler());
		favoritesPanel.add(canvas);
	}

	public static void fileTreeUpdateDoc(CaseNode node, boolean toolbarN,
			int window) throws IOException, CollabVizException {

		// centre the visualizatoin tree to the node
		fileTreeUpdateDoc(node, toolbarN, window, true);
	}

	public static void fileTreeUpdateDoc(CaseNode node, boolean toolbarN,
			int window, boolean rotateNodes) throws IOException,
			CollabVizException {

		// centre the visualizatoin tree to the node
		if (rotateNodes) {
			vizSetNoTabOpen(false);
			rotateVisualizationTree(node.getName());
		}
		updateDoc(node.getAbsolutePath());
	}

	public static void visualizationUpdateDoc(final String path)
			throws IOException, CollabVizException {
		// XXX: FOR NOW!!
		// toolbar = true
		// windows = 1
		updateDoc(getHtmlRootFolderPath() + path);
	}

	static void vizSetNoTabOpen(boolean b){
		visual.setNoTabOpen(b);
	}

	static void runVizAction (String action) {
		visual.runAction(action);
		docVizSplitPane.updateUI();
	}

	static void vizUnhide(){
		visual.unhide();
		docVizSplitPane.updateUI();
	}


	private static void rotateVisualizationTree(String nodeName) {
		/**
		 * 
		 * viz = null; // do not change this line: it helps the GC to collect
		 * the // old viz object faster // create new object viz =
		 * VizDemoRadial.demo( VizDemoRadial.DATA_FILE, "name", 360, 440 );
		 */
		// set focus on w/e file selected
		visual.externalSetFocus(nodeName);
		docVizSplitPane.updateUI();
		viz.invalidate();
		viz.repaint();
	}

	public static void updateDoc(final String absolutePath) throws IOException, CollabVizException {

		File f = new File(absolutePath);
		htmlFilePath = absolutePath;

		if (openTabs.contains(absolutePath)) {
			int index = openTabs.indexOf(absolutePath);
			multipleDocs.setSelectedIndex(index);
		} else {
			// Construct paint doc and add it to the UI hierarchy. 
			// Current hierarchy is like this:
			// JTabbledPane
			// --JSplitPane
			// ----JPanel (top half)
			// ------Highlight Button, Search Bar
			// ----JScrollPane
			// ------JDesktopPane
			// --------JPanel
			// ----------Margin area on left for annotations
			// ----------PaintDoc
			// --------User annotations

			JDesktopPane desktop = new JDesktopPane();
			desktop.setBackground(Color.white); // it's black by default which shows sometimes, using white hides it. 

			PaintDoc doc = new PaintDoc(absolutePath);
			doc.setPage(f.toURI().toURL());
			doc.setDragEnabled(true);
			doc.setEditable(false);


			// We use a separate container to hold the document because we want to be able to add a left margin 
			// so that annotations can go there. We could have modified the margin in the html documents instead,
			// but as of now some of the documents are created with MS word, which means they contain a ton of 
			// convoluted tags that are next to impossible to decipher. Following the KISS principle, it is far 
			// easier to just do this and add a left margin. Plus, we don't have to modify a whole bunch of html
			// documents each time we change our mind about the margin; we can just change the constant 1 time at 1 place.  
			final JPanel docContainer = new JPanel();
			docContainer.setFocusable(true);
			docContainer.addMouseListener(new MouseAdapter(){
				@Override
				public void mouseClicked(MouseEvent me){
					docContainer.requestFocusInWindow();
				}
			});
			docContainer.setLayout(new BorderLayout());
			JPanel blankArea = new JPanel();

			final int docwidth = getDocWidth(absolutePath);
			int docheight = getDocHeight(absolutePath);

			docContainer.add(doc, BorderLayout.CENTER);
			Dimension docSize = new Dimension(docwidth + ANNOTATION_MARGIN,docheight);

			blankArea.setPreferredSize(new Dimension(ANNOTATION_MARGIN, docheight));
			blankArea.setBackground(Color.white);
			docContainer.add(blankArea, BorderLayout.WEST);

			docContainer.setBounds(0, 0, (int) docSize.getWidth(), (int) docSize.getHeight());

			desktop.add(docContainer);
			desktop.setPreferredSize(docSize);

			JSplitPane jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
			jsp.setDividerLocation(50); 


			SearchBar search = new SearchBar();
			search.addDocumentListener(new DocumentSearchDocumentListener(doc));
			search.addDocumentListener(new QueryLoggerDocumentListener(Location.Documents));
			search.addUserLogClickListener(Location.Documents);

			JPanel panel = new JPanel();
			panel.setLayout(new BorderLayout(0, 0));
			panel.add(search, BorderLayout.EAST);

			Box buttonBox = new Box(BoxLayout.X_AXIS);
			HighlightToggle toggle = HighlightToggle.getInstance(FilenameUtils.getBaseName(absolutePath));
			buttonBox.add(toggle);
			panel.add(buttonBox, BorderLayout.WEST);
			doc.addCaretListener(new HighlightListener(doc, desktop, toggle));

			JScrollPane scroll = new JScrollPane(desktop);
			jsp.setTopComponent(panel);
			jsp.setBottomComponent(scroll);


			// this is hackish because openTabs.add MUST be called 
			// before updating the tabbedPane, or the changedEvent 
			// handler in AllComponets doesn't work correctly
			// as it depends on tabbedPane and openTabs having 
			// corresponding elements.
			openTabs.add(absolutePath);
			String fileName = FilenameUtils.getBaseName(absolutePath);
			multipleDocs.addTab(fileName.length() > MAX_TAB_NAME_LENGTH ? fileName.substring(0, MAX_TAB_NAME_LENGTH) : fileName, jsp);
			multipleDocs.setSelectedIndex(openTabs.indexOf(absolutePath));
			updatedDocument = doc;
		}
	}

	private static int getDocWidth(String absPath){
		String name = FilenameUtils.getName(absPath).toLowerCase();
		if (name.contains("bus")){
			return 550;
		} else if (name.contains("interview")){
			return 1150;
		}
		return 1350;
	}

	private static int getDocHeight(String absPath){
		String name = FilenameUtils.getName(absPath).toLowerCase();
		if (name.contains("bus")){
			return 1300;
		}  else if (name.contains("report")){
			return 600;
		} else if (name.contains("interview")){
			return 600;
		}
		return 1100;
	}

	public static PaintDoc getUpdatedDocument()
	{
		return updatedDocument;
	}


	static GridLayout grid = new GridLayout(2, 1, 0, 0);

	private static JPanel favorites = new JPanel( /* grid */);

	private static JPanel saveBarPanel = new JPanel();

	private static JEditorPane saveTextPanel = new JEditorPane();

	JScrollPane saveScrollPanel = new JScrollPane(saveTextPanel);

	private static JProgressBar progressBar = null;

	public static void createProgressBar(String title) {
		progressBar = new JProgressBar(0, 10);
		progressBar.setStringPainted(true);
		Border border = BorderFactory.createTitledBorder(title);
		progressBar.setBorder(border);
		saveBarPanel.add(progressBar, BorderLayout.NORTH);
	}

	public static JProgressBar getProgressBar() {
		return progressBar;
	}

	public static JPanel getSaveBarPanel() {
		return saveBarPanel;
	}

	public static JEditorPane getSaveTextPanel() {
		return saveTextPanel;
	}

	private static void updateNotesHighlighting (PaintDoc doc) {

	}

	public static void highlightDoc(PaintDoc doc, String annotation) {
		Highlighter.HighlightPainter myHighlightPainter = new TextHighlighter(
				color_text_highlight	); 
		/* Color Change 
			 Previously: 
			 public static void highlightDoc(PaintDoc doc, String annotation) {
				Highlighter.HighlightPainter myHighlightPainter = new TextHighlighter(
					Color.yellow	); 

		 */
		// highlight the text that is displayed on screen currently
		try {
			Highlighter hilite;
			Document docum;
			docum = doc.getDocument();
			hilite = doc.getHighlighter();
			System.out.println(doc.getCaret().getMagicCaretPosition());


			String text = docum.getText(0, docum.getLength());
			System.out.println(text);
			int i = 0;
			System.out.println(text.length());
			int pos = 0;
			int temPos = -1;
			// Search for pattern
			while ((pos = text.indexOf(annotation, pos)) >= 0 && i < text.length()%annotation.length()) 
				// the first part before the && should exit the while loop at the correct time, but sometimes it did
				// not so the second part will never make it miss a instance of the annotation and will make it exit 
				// the while loop as well
			{
				// Create highlighter using private painter and apply around
				// pattern
				hilite.addHighlight(pos, pos + annotation.length(),
						myHighlightPainter);
				//temPos = pos;
				pos = pos + annotation.length() + 1;
				i++;
			}
			doc.modelToView(temPos);
			doc.repaint();
			AllComponents.docVizSplitPane.repaint();
		} catch (BadLocationException e) {
			System.out.println("WARN: error while highlighting...");
			// throw new CollabVizException(e);
		}
	}


	/*
	public static void highlightAnnotations(List<AnnotationTag> annoList) {
		if (annoList == null || annoList.isEmpty()) {
			return;
		}
		removeHighlights(document);
		for (AnnotationTag annot : annoList) {
			try {
				highlight(multipleDocs, annot.getKey(), Color.yellow);
			} catch (Throwable th) {
				th.printStackTrace();
			}
		}
	}
	 */

	/*
	public static List<String> listXmlFilesForHtml(String htmlFilePath)
	throws CollabVizException {
		if (htmlFilePath == null || StringUtils.isEmpty(htmlFilePath)) {
			return null;
		}
		String htmlFileName[] = new File(htmlFilePath).getName().split(
				CollabVizConstants.DOT_REGEX);
		StringBuffer htmlDir = new StringBuffer(PropertyLoaderUtil
				.getProp(CollabVizConstants.XML_FILES_FOLDER_PATH));
		htmlDir.append(CollabVizConstants.FILE_DELIMITER);
		htmlDir.append(htmlFileName[0]);

		FilenameFilter filter = new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				String tokens[] = name.split(CollabVizConstants.DOT_REGEX);
				if (tokens == null || tokens.length != 2) {
					return false;
				}
				if ("xml".equals(tokens[1])) {
					return true;
				}
				return false;
			}
		};

		File htmlDirName = new File(htmlDir.toString());
		String tempFileList[] = htmlDirName.list(filter);
		List<String> resultList = new ArrayList<String>();
		if (tempFileList != null && tempFileList.length > 0) {

			resultList = Arrays.asList(tempFileList);
		}

		return resultList;
	}
	 */


	private static Point highlight(ClosableTabbedPane tabbedPane,
			String pattern, Color color) throws CollabVizException {
		JSplitPane splitPane = (JSplitPane) tabbedPane.getSelectedComponent();
		JScrollPane textScroll = (JScrollPane) splitPane.getRightComponent();
		JTextComponent textComp = (JTextComponent) textScroll.getViewport()
				.getView();

		Highlighter.HighlightPainter myHighlightPainter = new TextHighlighter(
				color);
		Point result = new Point();

		// highlight the text that is displayed on screen currently
		pattern = pattern.toLowerCase();
		try {

			Highlighter hilite = textComp.getHighlighter();
			Document doc = textComp.getDocument();
			String text = doc.getText(0, doc.getLength());
			text = text.toLowerCase();
			int pos = 0;
			int temPos = -1;
			// Search for pattern
			while ((pos = text.indexOf(pattern, pos)) >= 0) {
				// Create highlighter using private painter and apply around
				// pattern

				hilite.addHighlight(pos, pos + pattern.length(),
						myHighlightPainter);
				temPos = pos;
				pos += pattern.length();
			}

		} catch (BadLocationException e) {
			System.out.println("WARN: error while highlighting...");
			throw new CollabVizException(e);
		}
		return result;
	}

	@Override
	public void mouseClicked(MouseEvent e) {
	}

	@Override
	public void mouseEntered(MouseEvent e) {

	}

	@Override
	public void mouseExited(MouseEvent e) {

	}

	@Override
	public void mousePressed(MouseEvent e) {

	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	public static void removeHighlights(JTextComponent textComp) {
		Highlighter hilite = textComp.getHighlighter();

		Highlighter.Highlight[] hilites = hilite.getHighlights();

		if (hilites.length == 0) {
			return;
		}

		for (int i = 0; i < hilites.length; i++) {
			hilite.removeHighlight(hilites[i]);
		}
		// added here for temp fix
		Component compoList[] = document.getComponents();
		if (compoList != null && compoList.length > 0) {
			for (Component compo : compoList) {
				if (compo instanceof JLabel) {
					compo.setEnabled(false);
					document.remove(compo);
				}
			}
		}
	}


	private static String getDateString(String timeStamp) {
		if (timeStamp == null || StringUtils.isEmpty(timeStamp)) {
			return (new Date().toString());
		}
		DateFormat formatter = new SimpleDateFormat(
				CollabVizConstants.DATE_FORMAT);
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(Long.parseLong(timeStamp));
		return (formatter.format(cal.getTime()));
	}


	public static void highlightAnnotInHistoryTable(String key, String value) {
		//		if (key == null || StringUtils.isEmpty(key) || value == null
		//				|| StringUtils.isEmpty(value)) {
		//			return;
		//		}
		//		HashSet<String> cellValueSet = new HashSet<String>();
		//		cellValueSet.add(key);
		//		cellValueSet.add(value);
		//		Rectangle rect = notesArea.highlightTextSet(cellValueSet);
		//		if (rect != null) {
		//			notesArea.getTable().scrollRectToVisible(rect);
		//		}
	}

	/*
	private static void loadHistoryTable(FileTag fileTag, Set<String> highText)
	throws CollabVizException {
		if (htmlFilePath == null || StringUtils.isEmpty(htmlFilePath)) {
			System.out.println("ERROR: No Html file is loaded...");
			return;
		}
		// Get the path of the file containing all the notes. 
		if (historyFilePath == null || StringUtils.isEmpty(historyFilePath)) {
			StringBuffer historyFile = new StringBuffer(propLoader
					.getProp(CollabVizConstants.XML_FILES_FOLDER_PATH));
			historyFile.append(CollabVizConstants.FILE_DELIMITER);
			historyFile.append(CollabVizConstants.HISTORY_FILE_NAME);
			historyFilePath = historyFile.toString();
		}

		hisFileTag = (UserNoteCollection) xmlService.unmarshall(historyFilePath);
		if (hisFileTag == null) {
			hisFileTag = new UserNoteCollection();
			System.out.println("WARN: No history to be loaded.");
		}

		historyRenderer.setFileTag(fileTag);
		// Set the data. 
		historyRenderer.setHistoryTag(hisFileTag);
		historyRenderer.loadDataOri(highText);
		historyRenderer.setViewportViewForHistory(historyScroll);
		JScrollBar scrollBar = historyScroll.getVerticalScrollBar();
		scrollBar.setValue(scrollBar.getMaximum());

		// for the search within history content
		historyRenderer.loadData(highText, null);
	}
	 */

	public static NotesArea getNotesArea() {
		return notesArea;
	}

	public static FileTree getFileTree() {
		return (FileTree) directory;
	}

	public static JEditorPane getDocumentPane() {
		return (JEditorPane) document;
	}
	public static PaintDoc getDocumentPaintDoc(){
		return document;
	}

	public static ClosableTabbedPane getMultipleDocs() {
		return multipleDocs;
	}

	private static String previousAbsPath = null;
	private static String currentAbsPath = null;

	public static String getPreviousPath() {
		return previousAbsPath;
	}

	public static void saveCurrentPath(String absPath) {
		previousAbsPath = currentAbsPath;
		currentAbsPath = absPath;
	}

	/**
	 * This is a hack of the getCurrentPath() method. 
	 * @return
	 */
	//	public static String getCurrentPathForNoteArea () {

	//	}

	public static String getCurrentPath() {
		return currentAbsPath;
	}
}

